const fs = require("fs-extra");
const {
  // vue 提供编译单文件组件的方法
  parse,
  // 生成脚本代码， 编译脚本
  compileScript,
  // 重写导出方法
  rewriteDefault,
  //编译模板
  compileTemplate,
  //编译样式
  compileStyleAsync,
} = require("vue/compiler-sfc");
// 根据传入值，实现唯一值
const hash = require("hash-sum");
const dedent = require("dedent");
const descriptorCache = new Map();
function vue() {
  let root; //根目录
  return {
    name: "vue",
    async config(config) {
      root = config.root;
      return {
        define: {
          // 表示启用 options api
          __VUE_OPTIONS_API__: true,
          // 开发环境启用开发工具
          __VUE_PROD_DEVTOOLS__: false,
        },
      };
    },
    async load(id) {
      const { filename, query } = parseVueRequest(id);
      if (query.has("vue")) {
        const descriptor = await getDescriptor(filename);
        if (query.get("type") === "style") {
          let styleBlock = descriptor.styles[Number(query.get("index"))];
          if (styleBlock) {
            return { code: styleBlock.content }; //h1{color:red}
          }
        }
      }
    },
    async transform(code, id) {
      const { filename, query } = parseVueRequest(id); // /src/App.vue
      if (filename.endsWith(".vue")) {
        // 请求的是样式文件
        if (query.get("type") === "style") {
          const descriptor = await getDescriptor(filename);
          let result = await transformStyle(
            code,
            descriptor,
            Number(query.get("index"))
          );
          return result;
        } else {
          // 转换 .vue 文件
          return await transformMain(code, filename);
        }
      }
      return null;
    },
  };
}
async function transformStyle(code, descriptor, index) {
  const styleBlock = descriptor.styles[index];
  const result = await compileStyleAsync({
    filename: descriptor.filename, //文件名
    source: code, //样式的源代码
    id: `data-v-${descriptor.id}`, //为了实现局部作用域，需要一个唯一的ID
    scoped: styleBlock.scoped, //实现局部样式 scoped
  });
  let styleCode = result.code;
  return {
    code: `
     var style = document.createElement('style');
     style.innerHTML = ${JSON.stringify(styleCode)};
     document.head.appendChild(style);
  `,
  };
}
/**
 * 转换 .vue 文件
 * @param {*} source 源代码
 * @param {*} filename 文件名
 * @returns
 */
async function transformMain(source, filename) {
  // 创建描述符,组件描述符
  const descriptor = await getDescriptor(filename);
  // 生成js脚本代码
  const scriptCode = genScriptCode(descriptor, filename);
  // 生成html模板代码
  const templateCode = genTemplateCode(descriptor, filename);
  // 生成css模板代码
  const styleCode = genStyleCode(descriptor, filename);
  let code = [
    styleCode,
    scriptCode,
    templateCode,
    " _sfc_main.render = render;",
    "export default _sfc_main;",
  ].join("\n");
  return { code };
}
function genStyleCode(descriptor, filename) {
  let styleCode = "";
  if (descriptor.styles.length > 0) {
    // 一个 vue 文件，可能会有多个 style
    descriptor.styles.forEach((style, index) => {
      const query = `?vue&type=style&index=${index}&lang.css`;
      const styleRequest = (filename + query).replace(/\\/g, "/");
      //import "/src/App.vue?vue&type=style&index=0&lang.css"
      styleCode += `\nimport "${styleRequest}"`;
    });
    return styleCode;
  }
}
function genTemplateCode(descriptor, id) {
  let content = descriptor.template.content;
  let result = compileTemplate({ source: content, id });
  return result.code;
}
// 编译脚本
function genScriptCode(descriptor, id) {
  // js 会原样输出， ts才会编译
  let script = compileScript(descriptor, { id });
  // 重写导出方法  _sfc_main 用于重写变量名
  return rewriteDefault(script.content, "_sfc_main");
}
/**
 * 创建描述符,组件描述符
 * @param {*} filename
 * @returns
 */
async function getDescriptor(filename) {
  // 由于频繁读取，增加缓存
  let descriptor = descriptorCache.get(filename);
  // 有缓存，走缓存
  if (descriptor) return descriptor;
  //读取App.vue文件的内容
  const content = await fs.readFile(filename, "utf8");
  const result = parse(content, { filename });
  descriptor = result.descriptor;
  descriptor.id = hash(filename);
  // 没缓存，追加缓存
  descriptorCache.set(filename, descriptor);
  return descriptor;
}
// 处理 请求路径 路径path 和 query
function parseVueRequest(id) {
  // 路径 App.vue?id=1 ， filename=App.vue querystring='id:1'
  const [filename, querystring = ""] = id.split("?");
  // query={id:1}
  let query = new URLSearchParams(querystring); // 以前是用 qs，现在用
  return {
    filename,
    query,
  };
}
module.exports = vue;

/*
  const _sfc_main = {
    name: 'App'
  }
  import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "/node_modules/.vite50/deps/vue.js"
  function _sfc_render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock("h1", null, "App"))
  }
  _sfc_main.render = _sfc_render;
  export default _sfc_main;
*/
